﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Networking
{

    /// <summary>
    /// Pixels encoding types
    /// </summary>
    public enum EncodingType
    {
        BitMap,
        Jpeg
    }

    /// <summary>
    /// The infos about a rectangle
    /// </summary>
    public class RectangleInfo
    {
        /// <summary>
        /// Coordinates
        /// </summary>
        public Coords Coords    { get; set; }
        
        /// <summary>
        /// Size
        /// </summary>
        public Size Size        { get; set; }

        /// <summary>
        /// Data encoding
        /// </summary>
        public EncodingType Encoding { get; set; }

        /// <summary>
        /// Pixel data
        /// </summary>
        public byte[] Data      { get; set; }

        /// <summary>
        /// Creates a new instance of RectangleInfo with all the parameters provided
        /// </summary>
        /// <param name="Coords">Coordinates</param>
        /// <param name="Size">Size</param>
        /// <param name="Encoding">Data encoding</param>
        /// <param name="Data">Pixel data</param>
        public RectangleInfo(Coords Coords, Size Size, EncodingType Encoding, byte[] Data)
        {
            this.Coords = Coords;
            this.Size = Size;
            this.Encoding = Encoding;

            this.Data = Data;

        }
        /// <summary>
        /// Creates a new instance of RectangleInfo with no parameters
        /// </summary>
        public RectangleInfo()
        {
            //
        }

    }

    /// <summary>
    /// Packet of type FramebufferUpdateResponsePacket, the response of framebuffer update request 
    /// </summary>
    public class FramebufferUpdateResponsePacket : Packet
    {
        
        /// <summary>
        /// The updated rectangles 
        /// </summary>
        public RectangleInfo[] Rectangles { get; private set; }

        /// <summary>
        /// Creates a new instance of FramebufferUpdateResponsePacket with the provided updated rectangles
        /// </summary>
        /// <param name="Rectangles">The updated rectangles</param>
        public FramebufferUpdateResponsePacket(RectangleInfo[] Rectangles)
            : base(PacketType.FramebufferUpdateResponse)
        {
            this.Rectangles = Rectangles;
        }

        /// <summary>
        /// Creates a new instance of FramebufferUpdateResponsePacket extracting all the parameters from the byte buffer
        /// </summary>
        /// <param name="buffer">The byte buffer containing the packet data</param>
        public FramebufferUpdateResponsePacket(byte[] buffer)
            : base(PacketType.FramebufferUpdateResponse, buffer)
        {
            //
        }


        /// <summary>
        /// Serializes the packet in order to send it
        /// </summary>
        /// <returns>The bytes of the packet</returns>
        public override byte[] Serialize()
        {
            

            MemoryStream memory = new MemoryStream();

            BinaryWriter writer = new BinaryWriter(memory);

            writer.Write((byte)this.Type);

            // Padding
            writer.Write(new byte[] { 0, 0, 0 });

            writer.Write((short)this.Rectangles.Count());

            // Rectangles
            for (int n = 0; n < this.Rectangles.Count(); n++)
            {
                writer.Write(this.Rectangles[n].Coords.X);
                writer.Write(this.Rectangles[n].Coords.Y);

                writer.Write(this.Rectangles[n].Size.Width);
                writer.Write(this.Rectangles[n].Size.Height);

                writer.Write((int)this.Rectangles[n].Encoding);

                writer.Write(this.Rectangles[n].Data.Length);

                writer.Write(this.Rectangles[n].Data);

            }

            writer.Close();

            return memory.ToArray();
        }


        /// <summary>
        /// Loads a packet from a byte buffer
        /// </summary>
        /// <param name="buffer">The data buffer</param>
        public override void Load(byte[] buffer)
        {

            MemoryStream memory = new MemoryStream(buffer);

            BinaryReader reader = new BinaryReader(memory);

            try
            {

                this.Type = (PacketType)reader.ReadByte();

                if (this.Type != PacketType.FramebufferUpdateResponse)
                    throw new PacketTypeMismatchException(PacketType.FramebufferUpdateResponse, this.Type);

                // padding
                reader.ReadBytes(3);

                int iRectanglesCount = reader.ReadInt16();

                this.Rectangles = new RectangleInfo[iRectanglesCount];

                for (int n = 0; n < iRectanglesCount; n++)
                {

                    this.Rectangles[n] = new RectangleInfo();

                    this.Rectangles[n].Coords = new Coords(reader.ReadInt16(), reader.ReadInt16());
                    this.Rectangles[n].Size = new Size(reader.ReadInt16(), reader.ReadInt16());

                    this.Rectangles[n].Encoding = (EncodingType)reader.ReadInt32();

                    int iDataLength = reader.ReadInt32();

                    this.Rectangles[n].Data = reader.ReadBytes(iDataLength);


                }
            }
            catch (IOException ex)
            {
                throw new CorruptedPacketException(PacketType.FramebufferUpdateResponse, "BinaryReader: " + ex.Message);
            }
            finally
            {
                reader.Close();
            }
        }
    }

}
